package com.submit.demo.service.impl;

import com.submit.demo.common.api.CommonPage;
import com.submit.demo.config.MinIOProperties;
import com.submit.demo.dto.SubmitterTaskData;
import com.submit.demo.dto.TaskInsertParam;
import com.submit.demo.model.*;
import com.submit.demo.repository.ColTaskRepository;
import com.submit.demo.repository.SubTaskRepository;
import com.submit.demo.repository.SubmitterRepository;
import com.submit.demo.repository.TaskRepository;
import com.submit.demo.service.TaskService;
import com.submit.demo.util.MinIOUtil;
import com.submit.demo.util.MongoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskRepository taskRepository;

    @Autowired
    private ColTaskRepository colTaskRepository;

    @Autowired
    private SubTaskRepository subTaskRepository;

    @Autowired
    private SubmitterRepository submitterRepository;

    @Autowired
    private MinIOProperties minIOProperties;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MongoUtil mongoUtil;

    @Override
    public String createTask(TaskInsertParam param) {
        Task task = new Task();
        task.setTitle(param.getTitle());
        task.setDescription(param.getDescription());
        task.setCreateTime(param.getCreateTime());
        task.setDeadline(param.getDeadline());
        task.setContent(param.getContent());
        task.setStatus(0);
        task = taskRepository.insert(task);
        ColTask colTask = colTaskRepository.findColTaskByCid(param.getCid());
        if(colTask == null){
            colTask = new ColTask();
            colTask.setCid(param.getCid());
            List<String> tids = new ArrayList<>();
            tids.add(task.getId());
            colTask.setTids(tids);
            colTaskRepository.insert(colTask);
            return task.getId();
        }
        colTask.getTids().add(task.getId());
        colTaskRepository.save(colTask);
        return task.getId();
    }

    @Override
    public Integer cancelTask(String tid) {
        Runnable r = () -> {
            List<Word> list = new ArrayList<>();
            Task task = taskRepository.findTaskById(tid);
            if(task.getWords() != null) list.addAll(task.getWords());
            List<SubTask> subTasks = subTaskRepository.findAllByTid(tid);
            ColTask colTask = colTaskRepository.findColTaskByTidsContains(tid);
            for(SubTask subTask : subTasks) {
                if(subTask.getWords() != null) list.addAll(subTask.getWords());
            }
            log.info("正在删除" + list);
            if(list.size() > 0) MinIOUtil.deleteWords(minIOProperties.getBucketName(), list);
            taskRepository.deleteById(tid);
            colTask.getTids().remove(tid);
            colTaskRepository.save(colTask);
            subTaskRepository.deleteAllByTid(tid);
        };
        new Thread(r).start();
        return 1;
    }

    @Override
    public Integer upload(MultipartFile[] words, String tid) {
        Task task = taskRepository.findTaskById(tid);
        List<Word> list = new ArrayList<>();
        for(MultipartFile word : words){
            Word w = new Word();
            String name = word.getOriginalFilename();
            w.setWord(name);
            w.setSubTime(new Date());
            list.add(w);
            try {
                MinIOUtil.upload(minIOProperties.getBucketName(), name, word.getInputStream(), word.getSize());
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(task.getWords() == null) task.setWords(new ArrayList<>());
        }
        task.getWords().addAll(list);
        taskRepository.save(task);
        return 1;
    }

    @Override
    public CommonPage<Task> selectTasksByCid(String cid, Integer currentPage, Integer pageSize) {
        ColTask colTask = colTaskRepository.findColTaskByCid(cid);
        if(colTask == null) return null;
        Query query = new Query(Criteria.where("id").in(colTask.getTids()));
        long count = mongoTemplate.count(query, Task.class);
        mongoUtil.start(currentPage, pageSize, query);
        List<Task> list = mongoTemplate.find(query, Task.class);
        CommonPage commonPage = mongoUtil.pageHelper(count, list);
        return commonPage;
    }

    @Override
    public CommonPage<Task> selectTasksBySid(String sid, Integer currentPage, Integer pageSize) {
        List<SubTask> list = subTaskRepository.findAllBySid(sid);
        List<String> tids = list.stream().map(SubTask::getTid).collect(Collectors.toList());
        Query query = new Query(Criteria.where("id").in(tids).and("status").gt(0));
        long count = mongoTemplate.count(query, Task.class);
        mongoUtil.start(currentPage, pageSize, query);
        List<Task> result = mongoTemplate.find(query, Task.class);
        CommonPage commonPage = mongoUtil.pageHelper(count, result);
        return commonPage;
    }

    @Override
    public Integer startTask(String tid) {
        Query query = new Query(Criteria.where("id").is(tid));
        Update update = new Update().set("status", 1);
        mongoTemplate.updateFirst(query, update, Task.class);
        return 1;
    }

    @Override
    public Integer pauseTask(String tid) {
        Query query = new Query(Criteria.where("id").is(tid));
        Update update = new Update().set("status", 3);
        mongoTemplate.updateFirst(query, update, Task.class);
        return 1;
    }

    @Override
    public CommonPage<Task> getList(Integer currentPage, Integer pageSize, Integer status) {
        Query query;
        if(status >= 0) query= new Query(Criteria.where("status").is(status));
        else query = new Query();
        long count = mongoTemplate.count(query, Task.class);
        mongoUtil.start(currentPage, pageSize, query);
        List<Task> result = mongoTemplate.find(query, Task.class);
        CommonPage commonPage = mongoUtil.pageHelper(count, result);
        return commonPage;
    }

    @Override
    public Task getTask(String id) {
        return taskRepository.findTaskById(id);
    }

    @Override
    public Integer changeTaskFileName(String tid, String title) {
        Query query = new Query(Criteria.where("id").is(tid));
        Update update = new Update().set("title", title);
        mongoTemplate.updateFirst(query, update, Task.class);
        return 1;
    }

    @Override
    public Integer changeDate(String tid, Date date) {
        Query query = new Query(Criteria.where("id").is(tid));
        Update update = new Update().set("deadline", date);
        mongoTemplate.updateFirst(query, update, Task.class);
        return 1;
    }

    @Override
    public SubmitterTaskData selectSubTaskByTid(String sid, String tid) {
        Task task = taskRepository.findTaskById(tid);
        Submitter submitter = submitterRepository.findById(sid).get();
        SubTask subTask = subTaskRepository.findSubTaskBySidAndTid(sid, tid);
        SubmitterTaskData submitterTaskData = new SubmitterTaskData();
        submitterTaskData.setStatus(subTask.getStatus());
        submitterTaskData.setWords(subTask.getWords());
        submitterTaskData.setTask(task);
        submitterTaskData.setSubmitter(submitter);
        return submitterTaskData;
    }

    @Override
    public CommonPage<Submitter> getListByTid(String tid, Integer currentPage, Integer pageSize) {
        Query query = new Query(Criteria.where("tid").is(tid));
        long count = mongoTemplate.count(query, SubTask.class);
        mongoUtil.start(currentPage, pageSize, query);
        List<SubTask> list = mongoTemplate.find(query, SubTask.class);
        List<String> sids = list.stream().map(SubTask::getSid).collect(Collectors.toList());
        List<Submitter> submitters = mongoTemplate.find(new Query(Criteria.where("id").in(sids)), Submitter.class);
        return mongoUtil.pageHelper(count, submitters);
    }
}
